using System;
using System.Collections.Generic;
using System.Text;

namespace CodePlex.Resourceful.Amazon.SimpleDB
{
    public class SimpleDBClient : QueryAPIClient
    {

        public static readonly string DefaultServiceHost = "sdb.amazonaws.com";
        private static readonly string Version = "2009-04-15";
      
        public SimpleDBClient(string accessKeyID, string secretAccessKey, bool useSSL, string method)
            : base(accessKeyID,secretAccessKey,useSSL,method,DefaultServiceHost,Version)
        {
         
        }



        public ClientResponse CreateDomain(string domainName)
        {

            // The name of the domain to create. The name can range between 3 and 255 characters and can contain the following characters: a-z, A-Z, 0-9, '_', '-', and '.'. 

            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "CreateDomain";
            parameters["DomainName"] = domainName;

            return this.DoQueryRequest(parameters);

        
        }

        public ClientResponse DeleteDomain( string domainName)
        {
            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "DeleteDomain";
            parameters["DomainName"] = domainName;

            return this.DoQueryRequest( parameters);
        }


        public ClientResponse ListDomains()
        {
            return this.ListDomains( null, null);
        }
        public ClientResponse ListDomains( int? maxNumberOfDomains, string nextToken)
        {
            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "ListDomains";

            this.AddOptional(parameters, "MaxNumberOfDomains", maxNumberOfDomains);
            this.AddOptional(parameters, "NextToken", nextToken);

            return this.DoQueryRequest( parameters);
        }

        public ClientResponse DomainMetadata(string domainName)
        {

            
            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "DomainMetadata";
            parameters["DomainName"] = domainName;

            return this.DoQueryRequest(parameters);


        }




        public ClientResponse PutAttributes(string domainName, string itemName, params NameValue[] attributes)
        {

            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "PutAttributes";
            parameters["DomainName"] = domainName;
            parameters["ItemName"] = itemName;
            Fn.ForEachWithIndex(attributes, delegate(NameValue attribute, int i)
            {
                parameters["Attribute." + i + ".Name"] = attribute.Name;
                parameters["Attribute." + i + ".Value"] = attribute.Value;

                NewNameValue nnv = attribute as NewNameValue;
                if (nnv == null || !nnv.IsNew)
                    parameters["Attribute." + i + ".Replace"] = "true"; // replace=false is the sdb default, replace=true is our default
               

            });

           return this.DoQueryRequest(parameters);
        }


        public ClientResponse GetAttributes(string domainName, string itemName, params string[] attributeNames)
        {
            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "GetAttributes";
            parameters["DomainName"] = domainName;
            parameters["ItemName.0"] = itemName;

            Fn.ForEachWithIndex(attributeNames, delegate(string attributeName, int i)
            {
                parameters["AttributeName." + i] = attributeName;
            });

             return this.DoQueryRequest(parameters);
        }

        public ClientResponse DeleteAttributes(string domainName, string itemName, params NameOnly[] attributes)
        {
   
            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "DeleteAttributes";
            parameters["DomainName"] = domainName;
            parameters["ItemName"] = itemName;

            Fn.ForEachWithIndex(attributes, delegate(NameOnly attribute, int i)
            {
                parameters["Attribute." + i + ".Name"] = attribute.Name;
                NameValue nv = attribute as NameValue;
                if (nv != null)
                    parameters["Attribute." + i + ".Value"] = nv.Value;
            });

            return this.DoQueryRequest(parameters);

        }





        public ClientResponse Select(string selectExpression, string nextToken)
        {
            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "Select";
            parameters["SelectExpression"] = selectExpression;
            AddOptional(parameters, "NextToken", nextToken);
       
            return this.DoQueryRequest(parameters);
        }


        public ClientResponse BatchPutAttributes(string domainName, IEnumerable<ItemAndAttributes> items)
        {

            NameValuePairs parameters = new NameValuePairs();
            parameters["Action"] = "BatchPutAttributes";
            parameters["DomainName"] = domainName;

            Fn.ForEachWithIndex(items, delegate(ItemAndAttributes item, int j)
            {
         
               parameters["Item." + j + ".ItemName"] = item.ItemName;
               Fn.ForEachWithIndex(item.Attributes, delegate(NameValue attribute, int i)
               {
                   parameters["Item." + j + ".Attribute." + i + ".Name"] = attribute.Name;
                   parameters["Item." + j + ".Attribute." + i + ".Value"] = attribute.Value;

                   NewNameValue nnv = attribute as NewNameValue;
                   if (nnv == null || !nnv.IsNew)
                       parameters["Item." + j + ".Attribute." + i + ".Replace"] = "true"; // replace=false is the sdb default, replace=true is our default


               });

           });


          

            return this.DoQueryRequest(parameters);
        }
























        private ClientResponse DoQueryRequest( NameValuePairs parameters)
        {
            return this.DoQueryRequest("",parameters);
        }


        private void AddOptional(NameValuePairs nvp, string name, object value)
        {
            if (value != null)
            {
                nvp[name] = value.ToString();
            }
        }




        // old signing methods
        //private ClientResponse Do(string action, Action20<NameValuePairs> fn)
        //{
        //    NameValuePairs nvp = new NameValuePairs();
        //    nvp["AWSAccessKeyId"] = _accessKeyID;
        //    nvp["Timestamp"] = Utils.Iso8601Date(DateTime.Now);
        //    nvp["Version"] = "2009-04-15";
        //    nvp["Action"] = action;
        //    fn(nvp);
        //    SetSignatureVersion1(nvp);
        //    return this.GetRepresentation(GetRequest.Create("", nvp));
        // }

        //private void SetSignatureVersion0(NameValuePairs nvp)
        //{
        //    nvp["SignatureVersion"] = "0";
        //    string stringToSign = nvp["Action"] + nvp["Timestamp"];
        //    SetSignature(nvp, stringToSign);
        //}


        //private void SetSignatureVersion1(NameValuePairs nvp)
        //{
        //    nvp["SignatureVersion"] = "1";
        //    string stringToSign = Fn.Join("", Fn.Select<string, string>(Fn.OrderBy(nvp.Keys), delegate(string key)
        //    {
        //        return key + nvp[key];
        //    }));
        //    SetSignature(nvp, stringToSign);
        //}

        //private void SetSignature(NameValuePairs nvp, string stringToSign)
        //{
        //    nvp["Signature"] = Utils.ToBase64(Utils.ToHMACSHA1(Encoding.UTF8, _secretAccessKey, stringToSign));
        //}

    }

}
